package com.ruoyi.common.json;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.function.Supplier;

@Slf4j
public class JsonUtil {

    public static JsonList toJsonList(String value, Supplier<JsonList> defaultSuppler) {
        if (StringUtils.isBlank(value)) {
            return defaultSuppler.get();
        }
        try {
            return toJavaObject(value, JsonList.class);
        } catch (Exception e) {
            log.error("toList exception\n" + value, e);
        }
        return defaultSuppler.get();
    }

    public static JsonList toJsonList(Object value, Supplier<JsonList> defaultSuppler) {
        if (value == null) {
            return defaultSuppler.get();
        }
        return toJsonList(toJSONString(value), defaultSuppler);
    }


    public static JsonList toJsonList(String value) {
        return StringUtils.isNotBlank(value) ? toJsonList(value, () -> null) : null;
    }

    public static JsonList toJsonList(Object value) {
        return value != null ? toJsonList(value, () -> null) : null;
    }


    // 加载速度太慢了，放在静态代码块中
    // private static final ObjectMapper mapper = new ObjectMapper();
    private static ObjectMapper mapper;
    private static ObjectMapper mapper_SNAKECASE;

    /**
     * 设置一些通用的属性
     */
    static {
        mapper = new ObjectMapper();
        mapper_SNAKECASE = new ObjectMapper();
        // 如果json中有新增的字段并且是实体类类中不存在的，不报错
//        mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
        // 如果存在未知属性，则忽略不报错
        mapper.findAndRegisterModules();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper_SNAKECASE.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper_SNAKECASE.findAndRegisterModules();
        // 允许key没有双引号
//        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // 允许key有单引号
//        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // 允许整数以0开头
//        mapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
        // 允许字符串中存在回车换行控制符
//        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        mapper_SNAKECASE.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    }

    public static String toJSONString(Object obj) {
        return obj != null ? toJSONString(obj, () -> "", false) : "";
    }

    public static String toFormatJSONString(Object obj) {
        return obj != null ? toJSONString(obj, () -> "", true) : "";
    }


    public static String toJSONString(Object obj, Supplier<String> defaultSupplier, boolean format) {
        try {
            if (obj == null) {
                return defaultSupplier.get();
            }
            if (obj instanceof String) {
                return obj.toString();
            }
            if (obj instanceof Number) {
                return obj.toString();
            }
            if (format) {
                return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            }
            return mapper.writeValueAsString(obj);
        } catch (Throwable e) {
            log.error(String.format("toJSONString %s", obj != null ? obj.toString() : "null"), e);
        }
        return defaultSupplier.get();
    }

    public static <T> T toJavaObject(String value, Class<T> tClass) {
        return StringUtils.isNotBlank(value) ? toJavaObject(value, tClass, () -> null) : null;
    }

    public static <T> T toJavaObject(Object obj, Class<T> tClass) {
        return obj != null ? toJavaObject(toJSONString(obj), tClass, () -> null) : null;
    }

    public static <T> T toJavaObject(String value, Class<T> tClass, Supplier<T> defaultSupplier) {
        try {
            if (StringUtils.isBlank(value)) {
                return defaultSupplier.get();
            }
            return mapper.readValue(value, tClass);
        } catch (Throwable e) {
            log.error(String.format("toJavaObject exception: \n %s\n %s", value, tClass), e);
        }
        return defaultSupplier.get();
    }


    public static <T> T toJavaObject_SNAKECASE(String value, Class<T> tClass) {
        return StringUtils.isNotBlank(value) ? toJavaObject_SNAKECASE(value, tClass, () -> null) : null;
    }

    public static <T> T toJavaObject_SNAKECASE(Object obj, Class<T> tClass) {
        return obj != null ? toJavaObject_SNAKECASE(toJSONString(obj), tClass, () -> null) : null;
    }

    public static <T> T toJavaObject_SNAKECASE(String value, Class<T> tClass, Supplier<T> defaultSupplier) {
        try {
            if (StringUtils.isBlank(value)) {
                return defaultSupplier.get();
            }
            return mapper_SNAKECASE.readValue(value, tClass);
        } catch (Throwable e) {
            log.error(String.format("toJavaObject exception: \n %s\n %s", value, tClass), e);
        }
        return defaultSupplier.get();
    }

    public static <T> List<T> toJavaObjectList(String value, Class<T> tClass) {
        return StringUtils.isNotBlank(value) ? toJavaObjectList(value, tClass, () -> null) : null;
    }

    public static <T> List<T> toJavaObjectList(Object obj, Class<T> tClass) {
        return obj != null ? toJavaObjectList(toJSONString(obj), tClass, () -> null) : null;
    }

    public static <T> List<T> toJavaObjectList(String value, Class<T> tClass, Supplier<List<T>> defaultSupplier) {
        try {
            if (StringUtils.isBlank(value)) {
                return defaultSupplier.get();
            }
            JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, tClass);
            return mapper.readValue(value, javaType);
        } catch (Throwable e) {
            log.error(String.format("toJavaObjectList exception \n%s\n%s", value, tClass), e);
        }
        return defaultSupplier.get();
    }

    // 简单地直接用json复制或者转换(Cloneable)
    public static <T> T jsonCopy(Object obj, Class<T> tClass) {
        return obj != null ? toJavaObject(toJSONString(obj), tClass) : null;
    }

    public static JsonMap toJsonMap(String value) {
        return StringUtils.isNotBlank(value) ? toJsonMap(value, () -> null) : null;
    }

    public static JsonMap toJsonMap(Object value) {
        return value != null ? toJsonMap(value, () -> null) : null;
    }

    public static JsonMap toJsonMap(Object value, Supplier<JsonMap> defaultSupplier) {
        if (value == null) {
            return defaultSupplier.get();
        }
//        try {
//            if (value instanceof Map) {
//                return (JsonMap) value;
//            }
//        } catch (Exception e) {
//            log.info("fail to convert" + toJSONString(value), e);
//        }
        return toJsonMap(toJSONString(value), defaultSupplier);
    }

    public static JsonMap toJsonMap(String value, Supplier<JsonMap> defaultSupplier) {
        if (StringUtils.isBlank(value)) {
            return defaultSupplier.get();
        }
        try {
            return toJavaObject(value, JsonMap.class);
        } catch (Exception e) {
            log.error(String.format("toMap exception\n%s", value), e);
        }
        return defaultSupplier.get();
    }


}
